﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Spring.Data.NHibernate.Generic.Support;
using NHibernate;
using NHibernate.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Spring.Transaction.Interceptor;

namespace Dao.RepositoryBase.Implement
{
    /// <summary>
    /// Repository基类
    /// </summary>
    /// <typeparam name="T">实体</typeparam>
    public abstract class Repository<T> : HibernateDaoSupport, IRepository<T> where T : class
    {
        public virtual T Get(object id)
        {
            if (id == null) throw new ArgumentNullException("id");
            return this.HibernateTemplate.Get<T>(id);
        }
        [Transaction(Spring.Transaction.TransactionPropagation.Required, ReadOnly = false)]
        public virtual object Save(T model)
        {
            if (model == null) throw new ArgumentNullException("model");
            return this.HibernateTemplate.Save(model);
        }

        public virtual void Update(T model)
        {
            if (model == null) throw new ArgumentNullException("model");
            this.HibernateTemplate.Update(model);
        }

        public virtual void SaveOrUpdate(T model)
        {
            if (model == null) throw new ArgumentNullException("model");
            this.HibernateTemplate.SaveOrUpdate(model);
        }

        public virtual void Delete(T model)
        {
            if (model == null) throw new ArgumentNullException("model");
            this.HibernateTemplate.Delete(model);
        }

        public virtual void SubmitChanges()
        {
            this.Session.Flush();
        }

        public virtual IQueryable<T> GetAll()
        {
            return this.Session.Query<T>();
        }

        public virtual long GetCount<T>()
        {
            return this.Session.Query<T>().Count();
        }

        public virtual IQueryable<T> GetPageList(int firstResult, int maxResult)
        {
            var query = this.Session.Query<T>().Skip(firstResult).Take(maxResult);
            return query;
        }

        public virtual IQueryable<T> FindAll(PropertyInfo sort, string dir)
        {
            if (sort == null) throw new ArgumentNullException("sort");
            if (dir == null) throw new ArgumentNullException("dir");

            var source = this.Session.Query<T>();

            string sortingDir = (dir.ToUpper().Trim() == "ASC") ? "OrderBy" : "OrderByDescending";

            ParameterExpression paramOrderBy = Expression.Parameter(typeof(T), sort.Name);
            Expression exprOrderBy = Expression.Call(typeof(Queryable), sortingDir,
                new Type[] { typeof(T), sort.PropertyType },
                source.Expression, Expression.Lambda(Expression.Property(paramOrderBy, sort.Name), paramOrderBy));
            IQueryable<T> query = source.Provider.CreateQuery<T>(exprOrderBy);

            return query;
        }

        public virtual IQueryable<T> FindPageList(PropertyInfo sort, string dir, int firstResult, int maxResult)
        {
            if (sort == null) throw new ArgumentNullException("sort");
            if (dir == null) throw new ArgumentNullException("dir");

            var source = this.Session.Query<T>().Skip(firstResult).Take(maxResult);

            string sortingDir = (dir.ToUpper().Trim() == "ASC") ? "OrderBy" : "OrderByDescending";

            ParameterExpression paramOrderBy = Expression.Parameter(typeof(T), sort.Name);
            Expression exprOrderBy = Expression.Call(typeof(Queryable), sortingDir,
                new Type[] { typeof(T), sort.PropertyType },
                source.Expression, Expression.Lambda(Expression.Property(paramOrderBy, sort.Name), paramOrderBy));
            IQueryable<T> query = source.Provider.CreateQuery<T>(exprOrderBy);

            return query;
        }

        public virtual IQueryable<T> FindPageList(out long total, System.Reflection.PropertyInfo sort, string dir, int firstResult, int maxResult)
        {
            total = this.FindAll(sort, dir).Count<T>();
            return this.FindPageList(sort, dir, firstResult, maxResult);
        }
    }
}